package br.ufrj.dcc.ad.systems;

import java.util.ArrayList;
import java.util.List;

import br.ufrj.dcc.ad.metrics.Metrica;
import br.ufrj.dcc.ad.metrics.TempoFila;
import br.ufrj.dcc.ad.metrics.TempoServidor;
import br.ufrj.dcc.ad.metrics.TempoVao;

public class Cliente {
	private static Integer seqNome = new Integer(0);
	private String nome;
	/** Na prática é o indice da última fila que o cliente está/esteve. */
	private int tipoCliente;
	private double tempoConsumoRestante;
	private Double tempoUltimaEntradaServidor;
	private List<Double> temposUltimasEntradasFilas;
	private List<Double> temposEstadaFilas;
	private List<Double> temposConsumoServidor;
	private List<Double> temposVaosServidor;
	/**
	 * Inicializa um cliente do sistema.
	 * @param tempoConsumo O primeiro tempo de consumo no servidor.
	 */
	public Cliente(double tempoConsumo) {
		this.nome = getProximoNome();
		this.tipoCliente = 0;
		this.tempoConsumoRestante = tempoConsumo;
		//Inicialização de métricas
		this.temposUltimasEntradasFilas = new ArrayList<Double>();
		this.temposEstadaFilas = new ArrayList<Double>();
		this.temposConsumoServidor = new ArrayList<Double>();
		this.temposVaosServidor = new ArrayList<Double>();
		addTempoConsumoServidor(tempoConsumoRestante);
		//this.tempoUltimaEntradaServidor = 0.0; //Não deve ser iniciado, será pelo ServerAtendmentEvent.
	}
	
	private String getProximoNome() { 
		return "Cliente " + (++seqNome); 
	}
	/**
	 * Compara a prioridade entre dois clientes.
	 * @param cliente O cliente a ser comparado.
	 * @return <br>[inteiro positivo] Se this é mais prioritário que cliente.</br>
	 * 		   <br>[inteiro negativo] Se this é menos prioritário que cliente.</br>
	 *         <br>[0] Se os dois possuem a mesma prioridade.</br>
	 */
	public int comparePrioridade(Cliente cliente){
		return -(this.tipoCliente - cliente.getTipoCliente());
	}
	/**
	 * Retorna os tempos gastos em cada fila.
	 */
	public List<Metrica> getTemposNasFilas(){
		List<Metrica> tempoFilas = new ArrayList<Metrica>();
		
		for(Double tempoEstada: temposEstadaFilas){
			tempoFilas.add(new TempoFila(tempoEstada));
		}
		
		return tempoFilas;
	}
	/**
	 * Retorna os tempos gastos em cada serviço.
	 */
	public List<Metrica> getTemposNoServidor(){
		List<Metrica> temposServidor = new ArrayList<Metrica>();
		for(Double tempoConsumido: temposConsumoServidor){
			temposServidor.add(new TempoServidor(tempoConsumido));
		}
		return temposServidor;
	}
	/**
	 * Retorna os tempos gastos em vao no servidor não continuo.
	 */
	public List<Metrica> getTemposVaosNoServidor(){
		List<Metrica> temposVaos = new ArrayList<Metrica>();
		for(Double tempoVao: temposVaosServidor){
			temposVaos.add(new TempoVao(tempoVao));
		}
		return temposVaos;
	}

	public List<Double> getTemposUltimasEntradasFilas() {
		return temposUltimasEntradasFilas;
	}

	public void setTemposUltimasEntradasFilas(List<Double> temposEntradasFilas) {
		this.temposUltimasEntradasFilas = temposEntradasFilas;
	}
	
	public void addTempoConsumoServidor(double tempoConsumido){
		this.temposConsumoServidor.add(tempoConsumido);
	}
	
	public void addTempoVaoServidor(int indicePassadaServidor, double tempoVao){
		if(temposVaosServidor.size() > indicePassadaServidor){
			temposVaosServidor.set(indicePassadaServidor, temposVaosServidor.get(indicePassadaServidor) + tempoVao);
		}else{
			temposVaosServidor.add(indicePassadaServidor, tempoVao);
		}
	}
	
	public Double getTempoUltimaEntradaServidor() {
		return tempoUltimaEntradaServidor;
	}
	
	public void setTempoUltimaEntradaServidor(Double tempoEntradaServidor) {
		this.tempoUltimaEntradaServidor = tempoEntradaServidor;
	}

	public void setTempoConsumoRestante(double tempoConsumo) {
		this.tempoConsumoRestante = tempoConsumo;
	}

	public double getTempoConsumoRestante() {
		return tempoConsumoRestante;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public int getTipoCliente() {
		return tipoCliente;
	}

	public void setTipoCliente(int tipoCliente) {
		this.tipoCliente = tipoCliente;
	}
	
	public List<Double> getTemposEstadaFilas() {
		return temposEstadaFilas;
	}

	public void setTemposEstadaFilas(List<Double> temposEstadaFilas) {
		this.temposEstadaFilas = temposEstadaFilas;
	}
	
	public List<Double> getTemposConsumoServidor() {
		return temposConsumoServidor;
	}

	public void setTemposConsumoServidor(List<Double> temposConsumoServidor) {
		this.temposConsumoServidor = temposConsumoServidor;
	}
	
	public void addTempoEstadaFila(int indiceFila,double tempoEstada){
		if(temposEstadaFilas.size() > indiceFila){
			temposEstadaFilas.set(indiceFila, temposEstadaFilas.get(indiceFila) + tempoEstada);
		}else{
			temposEstadaFilas.add(indiceFila, tempoEstada);
		}
		
	}
	public List<Double> getTemposVaosServidor() {
		return temposVaosServidor;
	}

	public void setTemposVaosServidor(List<Double> temposVaosServidor) {
		this.temposVaosServidor = temposVaosServidor;
	}
	public static void resetSeqNum(){
		seqNome = new Integer(0);
	}
}
